﻿using System;
using System.Collections.Generic;
using System.IO.Ports;
using System.Net;
using System.Net.NetworkInformation;
using System.Net.Sockets;
using System.Text;

namespace Commnunications
{
    public class ChannelFactory
    {
        /// <summary>
        /// 创建tcp连接并连接，读写超时默认5000
        /// </summary>
        /// <param name="ip"></param>
        /// <param name="port"></param>
        /// <param name="connectTimeout"></param>
        /// <param name="action">修改选项配置</param>
        /// <returns></returns>
        public static TcpHandle CreateTcp(string ip, int port, int connectTimeout, int timeout = 5000, Action<Socket> action = null)
        {
            var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            //socket.Connect(ip, port);
            //m_ConnectHandle.NoDelay = true;
            //if (ConnectAsync(ip, port, connectTimeout, ref socket))
            //{
            if (action != null)
            {
                //serverSocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
                action(socket);
            }
            //socket.ReceiveTimeout = timeout;
            //socket.SendTimeout = timeout;
            //}
            return new TcpHandle(socket);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="port">端口号</param>
        /// <param name="host">如果ip为127.0.0.1则监控本地所有网卡的端口</param>
        /// <param name="action">修改选项配置</param>
        /// <returns></returns>
        public static UdpSerialHandle CreateUdpAndBind(int port, string host = "127.0.0.1", Action<Socket> action = null)
        {
            IPAddress hostAddr = "127.0.0.1" == host ? IPAddress.Any : IPAddress.Parse(host);
            var socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
            if (action != null)
            {
                //serverSocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
                action(socket);
            }
            IPEndPoint serverPoint = new IPEndPoint(hostAddr, port);
            socket.Bind(serverPoint);
            //socket.ReceiveTimeout = timeout;
            return new UdpSerialHandle(socket);
        }
        /// <summary>
        /// 创建串口
        /// </summary>
        /// <param name="comName"></param>
        /// <param name="baudRate"></param>
        /// <param name="dataBits"></param>
        /// <param name="parity"></param>
        /// <param name="stopBits"></param>
        /// <param name="timeout"></param>
        /// <returns></returns>
        public static ChannelHandle CreateSerial(string comName, int baudRate, int dataBits, Parity parity, StopBits stopBits, int timeout = 5000)
        {
            var serial = new SerialPort();
            serial.PortName = comName;
            serial.BaudRate = baudRate;
            serial.DataBits = dataBits;
            serial.Parity = parity;
            serial.StopBits = stopBits;
            serial.ReadTimeout = serial.WriteTimeout = timeout;
            return new UdpSerialHandle(serial);
        }
        /// <summary>
        /// 异步连接
        /// </summary>
        /// <param name="ip"></param>
        /// <param name="port"></param>
        /// <param name="timeout"></param>
        /// <param name="socket"></param>
        /// <returns></returns>
        public static bool ConnectAsync(string ip, int port, int timeout, ref Socket socket)
        {
            var timeState = new TimerState() { Handle = socket };
            socket.BeginConnect(ip, port, iar =>
            {
                var client = (TimerState)iar.AsyncState;
                try
                {
                    client.Handle.EndConnect(iar);
                }
                catch (Exception)
                {
                    client.IsTimeout = true;
                    //logger?.Error("brother ConnectAsync error:{0}", e.ToString());
                }
                finally
                {
                    client.ConDone.Set();
                }
            }, timeState);
            return timeState.ConDone.WaitOne(timeout) && !timeState.IsTimeout;
        }
        public static bool Ping(string ip, int timeout = 5000)
        {
            bool isOk = false;
            try
            {
                using (Ping pingSender = new Ping())
                {
                    //Ping 选项设置
                    PingOptions options = new PingOptions
                    {
                        DontFragment = true
                    };
                    string data = "";
                    byte[] buffer = Encoding.ASCII.GetBytes(data);
                    //调用同步 send 方法发送数据,将返回结果保存至PingReply实例
                    PingReply reply = pingSender.Send(ip, timeout, buffer, options);
                    isOk = reply.Status == IPStatus.Success;
                }
            }
            catch (Exception)
            {
            }
            return isOk;
        }
    }
}
